﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

///This class will invoke a pushable entity at the command of the collision map.
namespace MyImaginaryFriends_Redux.Screens.GamePlayScreen_Classes
{
    
    enum BoxType//not necessarily a box, could be a chair, etc.
    {
        LightObject = 1,
        MediumObject = 2,
        HeavyObject = 3,
    }

    class PushableEntity
    {
        #region Variables
      
      
        public Vector2 v2_Position
        {
            get { return v2_position; }
            set { v2_position = value; }
        }
        Vector2 v2_position;

        public Vector2 v2_Velocity
        {
            get { return v2_velocity; }
            set { v2_velocity = value; }
        }
        Vector2 v2_velocity;

        float f_movementX;

        float f_previousBottom;

        TileCollision TTBCollision;//tile to box collision.

        Texture2D t2d_SpritePic;
        BoxType boxType;

        public bool IsOnGround
        {
            get { return isOnGround; }
        }
        bool isOnGround;

        public bool b_isCollidingWith_TriggerA = false;

        public bool b_isCollidingWith_BlockRoom2_Trigger_To_RoomAGate = false;

        public bool b_isCollidingWith_RoomD_Trigger_To_BlockRoom1 = false;

        private Rectangle rec_LocalBounds;

        public Rectangle BoundingRectangle
        {
            get
            {
                int i_left = (int)Math.Round(v2_Position.X - (t2d_SpritePic.Width / 2)) + rec_LocalBounds.X;
                int i_top = (int)Math.Round(v2_Position.Y - (t2d_SpritePic.Height / 2)) + rec_LocalBounds.Y;

                return new Rectangle(i_left, i_top, rec_LocalBounds.Width, rec_LocalBounds.Height);
            }
        }

        #endregion

        public PushableEntity(ContentManager content, Vector2 sPosition, BoxType type)
        {
            //construct. may do the same deal as enemies.
            LoadContent(content, type);
            Spawn(sPosition, type);
        }

        public void Spawn(Vector2 sPosition, BoxType type)
        {
            v2_position.X = (sPosition.X * CollidingTile.i_TileWidth) + (t2d_SpritePic.Width / 2);
            v2_position.Y = (sPosition.Y * CollidingTile.i_TileHeight);

        }

        public void LoadContent(ContentManager content, BoxType type)
        {
            boxType = type;

            if (boxType == BoxType.LightObject)
            {
                t2d_SpritePic = content.Load<Texture2D>("GameplayScreenContent/Sprites/WoodenBox");

          

                int i_width = (int)t2d_SpritePic.Width;
                int i_left = 16;// (int)t2d_SpritePic.Width - i_width;
                int i_height = (int)t2d_SpritePic.Height;
                int i_top = (int)t2d_SpritePic.Height - i_height;

                rec_LocalBounds = new Rectangle(i_left, i_top, i_width, i_height);
            }
        }

        public void Update(GameTime gameTime, TileMap_Colliding collisionMap, PlayerEntity player, InputHandler input)
        {
            //apply physics//collision check
            //check player shit?//input from player
            ApplyPhysics(gameTime, collisionMap, player, input);
        }

        private void ApplyPhysics(GameTime gameTime, TileMap_Colliding collisionMap, PlayerEntity player, InputHandler input)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            Vector2 previousPosition = v2_Position;

            if (boxType == BoxType.LightObject)
            {
                v2_velocity.X += f_movementX * Physics.Pushable_Light_MoveAcceleration * elapsed;
                v2_velocity.Y = MathHelper.Clamp(v2_velocity.Y + Physics.GravityAcceleration * elapsed, -Physics.Pushable_Light_MaxFallSpeed, Physics.Pushable_Light_MaxFallSpeed);

                if (IsOnGround)
                {
                    v2_velocity.X *= Physics.GroundDragFactor;
                }
                else
                {
                    v2_velocity.X *= Physics.AirDragFactor;
                }

                v2_velocity.X = MathHelper.Clamp(v2_velocity.X, -Physics.Pushable_Light_MaxMoveSpeed, Physics.Pushable_Light_MaxMoveSpeed);

                v2_position += v2_velocity * elapsed;
                v2_Position = new Vector2((float)Math.Round(v2_Position.X), (float)Math.Round(v2_Position.Y));

                //handle collisions
                HandleCollisions(collisionMap, player, input);

                //if collisions stopped us from moving...
                if (v2_Position.X == previousPosition.X)
                    v2_velocity.X = 0;
                if (v2_Position.Y == previousPosition.Y)
                    v2_velocity.Y = 0;

            }

        }

        private void HandleCollisions(TileMap_Colliding collisionMap, PlayerEntity player, InputHandler input)
        {
            //b_isCollidingWith_TriggerA = false;
            b_isCollidingWith_BlockRoom2_Trigger_To_RoomAGate = false;
            b_isCollidingWith_RoomD_Trigger_To_BlockRoom1 = false;

            Rectangle rec_Bounds = BoundingRectangle;

            int i_leftTile = (int)Math.Floor((float)rec_Bounds.Left / CollidingTile.i_TileWidth);
            int i_rightTile = (int)Math.Ceiling(((float)rec_Bounds.Right / CollidingTile.i_TileWidth)) - 1;
            int i_topTile = (int)Math.Floor((float)rec_Bounds.Top / CollidingTile.i_TileHeight);
            int i_bottomTile = (int)Math.Ceiling(((float)rec_Bounds.Bottom / CollidingTile.i_TileHeight)) - 1;

            //reset flag for ground collision checks
            isOnGround = false;

            for (int y = i_topTile; y <= i_bottomTile; ++y)
            {
                for (int x = i_leftTile; x <= i_rightTile; ++x)
                {
                    TTBCollision = collisionMap.GetCollision(x, y);
                    #region if the tile is a colliding one

                    if (TTBCollision == TileCollision.Impassable || TTBCollision == TileCollision.Platform
                        || TTBCollision == TileCollision.DiagonalLeftStairs || TTBCollision == TileCollision.DiagonalRightStairs)
                    {
                        Rectangle rec_tileBounds = collisionMap.GetBounds(x, y);

                        Vector2 v2_depth = RectangleExtensions.GetIntersectionDepth(rec_Bounds, rec_tileBounds);

                        if (v2_depth != Vector2.Zero)
                        {
                            float f_absDepthX = Math.Abs(v2_depth.X);
                            float f_absDepthY = Math.Abs(v2_depth.Y);

                            //resolve along the shallow axis.
                            if (f_absDepthY < f_absDepthX || TTBCollision == TileCollision.Platform)
                            {
                                if (f_previousBottom <= rec_tileBounds.Top)
                                    isOnGround = true;

                                //ignore platforms
                                if ((TTBCollision == TileCollision.Impassable || IsOnGround))
                                {
                                    v2_Position = new Vector2(v2_Position.X, v2_Position.Y + v2_depth.Y);
                                    rec_Bounds = BoundingRectangle;
                                }
                            }
                            else if(TTBCollision == TileCollision.Impassable)
                            {
                                v2_Position = new Vector2(v2_Position.X + v2_depth.X, v2_position.Y);

                                rec_Bounds = BoundingRectangle;
                            }
                        }

                    }


                    #endregion

                    #region Else

                    else if (TTBCollision == TileCollision.Passable)
                    {
                        isOnGround = false;
                    }

                    else if (TTBCollision == TileCollision.RoomD_PlateTrigger_To_BlockRoom1Door)
                    {
                        b_isCollidingWith_RoomD_Trigger_To_BlockRoom1 = true;

                        player.b_RequestActivate_RoomD_PlateTrigger_Unlock_BlockRoom1 = true;
                    }
                        

                    else if (TTBCollision == TileCollision.BlockRoom2_Trigger_To_RoomAGate)
                    {
                       b_isCollidingWith_BlockRoom2_Trigger_To_RoomAGate = true;

                       player.b_RequestActivate_GateTrigger_BlockRoom2ToRoomA = true;
                    }

                    #endregion

                    #region player collision checks

                    if (BoundingRectangle.Intersects(player.BoundingRectangle))
                    {
                        player.b_IsCollidingWithPushableObject = true;
                        
                        HandleInput(input, player);

                      

                        ////player collision handling in here with box.
                        //Vector2 v2_depth = RectangleExtensions.GetIntersectionDepth(player.rec_Bounds, rec_Bounds);


                        //if (v2_depth != Vector2.Zero)
                        //{
                        //    float f_absDepthX = Math.Abs(v2_depth.X);
                        //    float f_absDepthY = Math.Abs(v2_depth.Y);

                        //    //resolve along the shallow axis.
                        //    if (f_absDepthY < f_absDepthX)
                        //    {
                        //        //if we crossed the top of the box...
                        //        if (player.f_previousBottom <= rec_Bounds.Top)
                        //            player.b_IsOnGround = true;

                        //        if (player.b_IsOnGround)
                        //        {
                        //            player.v2_Position = new Vector2(player.v2_Position.X, player.v2_Position.Y + v2_depth.Y);
                        //            //rec_bounds = bounding rectangle
                        //            player.rec_Bounds = player.BoundingRectangle;
                        //            rec_Bounds = BoundingRectangle;

                        //            f_movementX = 1.0f;
                        //        }

                        //    }
                        //    else if (f_absDepthY > f_absDepthX)
                        //    {
                        //        player.v2_Position = new Vector2(player.v2_Position.X + v2_depth.X, player.v2_Position.Y);
                        //        player.rec_Bounds = player.BoundingRectangle;
                        //        rec_Bounds = BoundingRectangle;
                        //        //new bounding rectangle

                        //        f_movementX = 1.0f;
                        //    }


                        //}

                       
                       

                    }
                    else
                    {
                        f_movementX = 0.0f;
                        player.b_IsCollidingWithPushableObject = false;
                    }


                    #endregion
                }
            }

            //set velocity to zero if on ground
            if (IsOnGround)
                v2_velocity.Y = 0.0f;

            //save the new bounds bottom
            f_previousBottom = rec_Bounds.Bottom;

        }
        private void HandleInput(InputHandler input, PlayerEntity player)
        {
            if (player.v2_Position.Y == v2_Position.Y)
            {
                if (player.v2_Position.X < v2_position.X)
                {
                    if (player.PushDirection == MoveDirection.right)
                    {
                        if (!input.GetKBStateHeld(Keys.X) || !input.GetGPStateHeld(Buttons.X))
                        {
                            if (input.GetKBState(Keys.Right) || input.GetGPState(Buttons.DPadRight))
                            {
                                f_movementX = 1.0f;
                            }

                            if (input.GetKBState(Keys.Left) || input.GetGPState(Buttons.DPadLeft))
                            {
                                f_movementX = 0.0f;
                            }
                        }
                        else if (input.GetKBStateHeld(Keys.X) || input.GetGPStateHeld(Buttons.X))
                        {
                            if (input.GetKBState(Keys.Right) || input.GetGPState(Buttons.DPadRight))
                            {
                                f_movementX = 0.0f;
                            }

                            if (input.GetKBState(Keys.Left) || input.GetGPState(Buttons.DPadRight))
                            {
                                f_movementX = -1.0f;
                            }
                        }
                    }
                }
                else if (player.v2_Position.X > v2_position.X)
                {
                    if (player.PushDirection == MoveDirection.left)
                    {
                        if (!input.GetKBStateHeld(Keys.X) || !input.GetGPStateHeld(Buttons.X))
                        {
                            if (input.GetKBState(Keys.Left) || input.GetGPState(Buttons.DPadLeft))
                            {
                                f_movementX = -1.0f;
                            }

                            if (input.GetKBState(Keys.Right) || input.GetGPState(Buttons.DPadRight))
                            {
                                f_movementX = 0.0f;
                            }
                        }
                        else if (input.GetKBStateHeld(Keys.X) || input.GetGPStateHeld(Buttons.X))
                        {
                            if (input.GetKBState(Keys.Left) || input.GetGPState(Buttons.DPadLeft))
                            {
                                f_movementX = 0.0f;
                            }

                            if (input.GetKBState(Keys.Right) || input.GetGPState(Buttons.DPadRight))
                            {
                                f_movementX = 1.0f;
                            }
                        }
                    }
                }
            }

           

            if (input.GetKBStateReleased(Keys.Left) && input.GetKBStateReleased(Keys.Right))
            {
                f_movementX = 0.0f;
            }
        }

        public void Draw(SpriteBatch spritebatch)
        {
            spritebatch.Draw(t2d_SpritePic, v2_position, Color.White);
          
        }

    }
}
